package com.ruoyi.business.rule.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ruoyi.business.base.JoBaseServiceImpl;
import com.ruoyi.business.customer.domain.JbOpportunity;
import com.ruoyi.business.customer.domain.JbOpportunityPolling;
import com.ruoyi.business.customer.domain.vo.JbCustomerPublicRule;
import com.ruoyi.business.customer.domain.vo.JbOpportunityPollingVo;
import com.ruoyi.business.customer.service.JbOpportunityPollingService;
import com.ruoyi.business.customer.service.JbOpportunityService;
import com.ruoyi.business.rule.domain.JbOpportunityRules;
import com.ruoyi.business.rule.mapper.JbOpportunityRulesMapper;
import com.ruoyi.business.rule.service.JbOpportunityRulesService;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商机规则Service业务层处理
 *
 * @author ruoyi
 * @date 2024-10-11
 */
@Service
@Slf4j
public class JbOpportunityRulesServiceImpl
        extends JoBaseServiceImpl<JbOpportunityRulesMapper, JbOpportunityRules>
        implements JbOpportunityRulesService
{
    @Autowired
    private JbOpportunityService jbOpportunityService;

    @Autowired
    private JbOpportunityPollingService jbOpportunityPollingService;

    @Autowired
    private ISysDeptService sysDeptService;

    @Autowired
    private ISysUserService sysUserService;

    @Override
    public void publicRule()
    {
        log.info("===========公共商机执行-{}", LocalDateTime.now());
        long currentTime = System.currentTimeMillis();
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                            	jo.id,
                            	jo.crop_ids,
                            	jo.customer_target,
                            	jo.other_labels,
                            	jor.dept_id,
                            	jor.execution_content
                            FROM
                            	jb_opportunity jo
                					INNER JOIN sys_dept sd on jo.dept_id=sd.parent_id
                            	INNER JOIN jb_opportunity_rules jor ON sd.dept_id = jor.dept_id
                            WHERE
                            	jo.del_flag = 0
                            	AND jo.opportunity_data_type = 0
                            	AND jo.opportunity_channel = 1001
                            	AND jor.execution_type = 1001
                            """);
        sql.add(String.format("	AND jor.rules_cod = '%s'", Constants.ONLINE_PUBLIC_OPPORTUNITY));
        List<JbCustomerPublicRule> list = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()),
                JbCustomerPublicRule.class);
        if (ObjectUtils.isNotEmpty(list))
        {
            Map<String, Long> ruleMap = Maps.newHashMap();
            //先判断那些是重复的
            list.forEach(a ->
            {
                JSONArray executionContent = JSONArray.parseArray(a.getExecutionContent());
                if (ObjectUtils.isNotEmpty(executionContent))
                {
                    for (int i = 0; i < executionContent.size(); i++)
                    {
                        JSONObject o = executionContent.getJSONObject(i);
                        StringBuilder builder = new StringBuilder();
                        if (ObjectUtils.isNotEmpty(o) && StringUtils.isNotBlank(o.getString("otherLabel")))
                        {
                            builder.append(o.getString("otherLabel"));
                        }
                        if (ObjectUtils.isNotEmpty(o) && StringUtils.isNotBlank(o.getString("target")))
                        {
                            builder.append(o.getString("target"));
                        }
                        if (ObjectUtils.isNotEmpty(o) && StringUtils.isNotBlank(o.getString("crop")))
                        {
                            builder.append(o.getString("crop"));
                        }
                        if (builder.length() > 0)
                        {
                            String ruleParam = builder.toString();
                            Long l = ruleMap.get(ruleParam);
                            if (ObjectUtils.isNotEmpty(l) && !l.equals(a.getDeptId()))
                            {
                                //表示一个规则匹配了多个部门，替换为0，后面有相同规则的还会执行此处，
                                //最后把values等0的不处理了。
                                ruleMap.replace(ruleParam, 0l);
                            } else
                            {
                                ruleMap.put(ruleParam, a.getDeptId());
                            }
                        }

                    }
                }
            });
            //获取线上公共商机，匹配规则
            List<JbOpportunity> updateOpport = Lists.newArrayList();
            list.forEach(a ->
            {
                Long deptId = isExist(a, ruleMap);
                if (ObjectUtils.isNotEmpty(deptId))
                {
                    //匹配成功，匹配的值是0表示一个规则有多个部门，不处理
                    JbOpportunity update = new JbOpportunity();
                    update.setId(a.getId());
                    update.setDepartmentId(deptId);
                    update.setOpportunityDataType(Constants.PUBLIC_NUMBER_1);
                    update.setDistributionType(Constants.PUBLIC_NUMBER_0.toString());
                    update.setDistributionTime(new Date());
                    updateOpport.add(update);
                }
            });
            log.info("==========执行更新归属部门操作内容-{}", updateOpport);
            if (ObjectUtils.isNotEmpty(updateOpport))
            {
                boolean b = jbOpportunityService.updateBatchById(updateOpport);
                log.info("==========执行更新归属部门操作结果-{}", b);
            }
        }
        log.info("===========公共商机执行结束-{},{}", LocalDateTime.now(), System.currentTimeMillis() - currentTime);
    }

    /**
     * 匹配规则是否成功
     *
     * @param rule
     * @param ruleMap
     * @return
     */
    private Long isExist(JbCustomerPublicRule rule, Map<String, Long> ruleMap)
    {
        List<List<String>> customerTarget = Lists.newArrayList();
        //其他标签会存在多个
        if (StringUtils.isNotBlank(rule.getOtherLabels()))
        {
            customerTarget.add(Arrays.asList(rule.getOtherLabels().split(",")));
        }
        //客户标签会存在多个
        if (StringUtils.isNotBlank(rule.getCustomerTarget()))
        {
            customerTarget.add(Arrays.asList(rule.getCustomerTarget().split(",")));
        }
        //客户作物会存在多个
        if (StringUtils.isNotBlank(rule.getCropIds()))
        {
            customerTarget.add(Arrays.asList(rule.getCropIds().split(",")));
        }
        if (ObjectUtils.isNotEmpty(customerTarget))
        {
            //处理不为空的数据，做笛卡尔积操作，用户和规则匹配
            List<String> allList = customerTarget.get(0);
            for (int i = 1; i < customerTarget.size(); i++)
            {
                List<String> currentList = customerTarget.get(i);
                allList = allList.stream().flatMap(a -> currentList.stream().map(b -> a + b))
                        .collect(Collectors.toList());
            }
            //验证是否和规则匹配成功，成功则返回ture
            for (String r : allList)
            {
                Long l = ruleMap.get(r);
                if (ObjectUtils.isNotEmpty(l) && l.intValue() != Constants.PUBLIC_NUMBER_0.intValue())
                {
                    //匹配成功，匹配的值是0表示一个规则有多个部门，不处理
                    return l;
                }
            }
        }
        return null;
    }

    @Override
    public void deptRule()
    {
        log.info("===========部门商机执行-{}", LocalDateTime.now());
        long currentTime = System.currentTimeMillis();
        //获取部门商机，部门商机规则和部门商机轮询记录，三表数据
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	ou.id,
                	ou.department_id AS departmentId,
                	op.id AS pid,
                	op.relation_id AS relationId\s
                FROM
                	jb_opportunity_rules orl
                	INNER JOIN jb_opportunity ou ON orl.dept_id = ou.department_id
                	LEFT JOIN jb_opportunity_polling op ON op.dept_id = ou.department_id\s
                	AND op.data_type = 0\s
                WHERE
                	orl.del_flag = '0'\s
                	AND orl.rules_cod = 'online_deptteam_opportunity'\s
                	AND orl.execution_type = 1001\s
                	AND ou.del_flag = '0'\s
                	AND ou.opportunity_data_type = 1\s
                	AND ou.opportunity_channel = '1001'
                """);
        List<JbOpportunityPollingVo> jbOpportunities = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()),
                JbOpportunityPollingVo.class);
        if (ObjectUtils.isNotEmpty(jbOpportunities))
        {
            List<Long> detpId =
                    jbOpportunities.stream().map(JbOpportunityPollingVo::getDepartmentId).distinct().collect(Collectors.toList());
            //获取部门的下级小组数据
            List<SysDept> teamList = sysDeptService.list(Wrappers.lambdaQuery(SysDept.class).in(SysDept::getParentId,
                    detpId).select(SysDept::getDeptId, SysDept::getParentId));
            if (ObjectUtils.isNotEmpty(teamList))
            {
                //按部门分割数据
                Map<Long, List<JbOpportunityPollingVo>> opporDept =
                        jbOpportunities.stream().collect(Collectors.groupingBy(JbOpportunityPollingVo::getDepartmentId));
                //按部门分割小组数据
                Map<Long, List<SysDept>> collect =
                        teamList.stream().collect(Collectors.groupingBy(SysDept::getParentId));
                List<JbOpportunity> updateOpport = Lists.newArrayList();
                List<JbOpportunityPolling> addUpdatePolling = Lists.newArrayList();
                for (Map.Entry<Long, List<JbOpportunityPollingVo>> entry : opporDept.entrySet())
                {
                    Long key = entry.getKey();
                    List<SysDept> sysDeptList = collect.get(key);
                    if (ObjectUtils.isEmpty(sysDeptList))
                    {
                        //此部门没有小组记录，则不处理
                        break;
                    }
                    List<JbOpportunityPollingVo> value = entry.getValue();
                    //单个部门循环处理归属小组
                    updateOpport(key, value, sysDeptList, updateOpport, addUpdatePolling);
                }
                log.info("===========部门商机更新商机数据-{}", updateOpport);
                if (ObjectUtils.isNotEmpty(updateOpport))
                {
                    jbOpportunityService.updateBatchById(updateOpport);
                }
                log.info("===========部门商机更新商机轮询记录数据-{}", addUpdatePolling);
                if (ObjectUtils.isNotEmpty(addUpdatePolling))
                {
                    jbOpportunityPollingService.saveOrUpdateBatch(addUpdatePolling);
                }
            }
        }
        log.info("===========部门商机执行结束-{},{}", LocalDateTime.now(), System.currentTimeMillis() - currentTime);
    }


    @Override
    public void teamRule()
    {
        log.info("===========小组商机执行-{}", LocalDateTime.now());
        long currenttime = System.currentTimeMillis();
        //获取小组商机，小组商机规则和小组商机轮询记录，三表数据
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	ou.id,
                	ou.team_id AS departmentId,
                	op.id AS pid,
                	op.relation_id AS relationId\s
                FROM
                	jb_opportunity_rules orl
                	INNER JOIN jb_opportunity ou ON orl.dept_id = ou.team_id
                	LEFT JOIN jb_opportunity_polling op ON op.dept_id = ou.team_id\s
                	AND op.data_type = 1\s
                WHERE
                	orl.del_flag = '0'\s
                	AND orl.rules_cod = 'online_deptteam_opportunity'\s
                	AND orl.execution_type = 1001\s
                	AND ou.del_flag = '0'\s
                	AND ou.opportunity_data_type = 2\s
                	AND ou.opportunity_channel = '1001'
                """);
        List<JbOpportunityPollingVo> jbOpportunities = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()),
                JbOpportunityPollingVo.class);
        if (ObjectUtils.isNotEmpty(jbOpportunities))
        {
            List<Long> detpId =
                    jbOpportunities.stream().map(JbOpportunityPollingVo::getDepartmentId).distinct().collect(Collectors.toList());
            //获取小组部门的人员
            List<SysUser> teamList = sysUserService.list(Wrappers.lambdaQuery(SysUser.class).in(SysUser::getDeptId,
                    detpId).select(SysUser::getUserId, SysUser::getDeptId));
            if (ObjectUtils.isNotEmpty(teamList))
            {
                //按部门分割数据
                Map<Long, List<JbOpportunityPollingVo>> opporDept =
                        jbOpportunities.stream().collect(Collectors.groupingBy(JbOpportunityPollingVo::getDepartmentId));
                //按部门分割小组数据
                Map<Long, List<SysUser>> collect = teamList.stream().collect(Collectors.groupingBy(SysUser::getDeptId));
                List<JbOpportunity> updateOpport = Lists.newArrayList();
                List<JbOpportunityPolling> addUpdatePolling = Lists.newArrayList();
                for (Map.Entry<Long, List<JbOpportunityPollingVo>> entry : opporDept.entrySet())
                {
                    Long key = entry.getKey();
                    List<SysUser> sysDeptList = collect.get(key);
                    if (ObjectUtils.isEmpty(sysDeptList))
                    {
                        //此部门没有人员记录，则不处理
                        break;
                    }
                    List<JbOpportunityPollingVo> value = entry.getValue();
                    //单个部门循环处理归属小组
                    updateOpportByUser(key, value, sysDeptList, updateOpport, addUpdatePolling);
                }
                log.info("===========小组商机更新商机数据-{}", updateOpport);
                if (ObjectUtils.isNotEmpty(updateOpport))
                {
                    jbOpportunityService.updateBatchById(updateOpport);
                }
                log.info("===========小组商机更新商机轮询记录数据-{}", addUpdatePolling);
                if (ObjectUtils.isNotEmpty(addUpdatePolling))
                {
                    jbOpportunityPollingService.saveOrUpdateBatch(addUpdatePolling);
                }
            }
        }
        log.info("===========小组商机执行结束-{},{}", LocalDateTime.now(), System.currentTimeMillis() - currenttime);
    }


    /**
     * 单个部门循环处理归属小组
     *
     * @param deptId
     * @param jbOpportunities
     * @param sysDeptList
     * @param updateOpport
     * @param pollingList
     */
    private void updateOpport(
            Long deptId,
            List<JbOpportunityPollingVo> jbOpportunities,
            List<SysDept> sysDeptList,
            List<JbOpportunity> updateOpport,
            List<JbOpportunityPolling> pollingList)
    {
        //循环最后一个执行小组的id
        JbOpportunityPollingVo jbOpportunityPollingVo = jbOpportunities.get(0);
        Long businessManagerId = jbOpportunityPollingVo.getRelationId();
        Long pid = jbOpportunityPollingVo.getPid();
        //默认小组的第一个
        int indexId = sysDeptList.get(0).getDeptId().intValue() - 1;
        if (ObjectUtils.isNotEmpty(businessManagerId))
        {
            //有轮询记录，继续走一下
            indexId = businessManagerId.intValue();
        }
        Long ruleDeptId = 0L;
        for (JbOpportunityPollingVo jbOpportunity : jbOpportunities)
        {
            for (int i = 0; i < sysDeptList.size(); i++)
            {
                SysDept sysDept = sysDeptList.get(i);
                if (sysDept.getDeptId().intValue() > indexId)
                {
                    //添加数据
                    JbOpportunity update = new JbOpportunity();
                    update.setId(jbOpportunity.getId());
                    update.setTeamId(sysDept.getDeptId());
                    update.setOpportunityDataType(Constants.PUBLIC_NUMBER_2);
                    update.setDistributionType(Constants.PUBLIC_NUMBER_0.toString());
                    update.setDistributionTime(new Date());
                    updateOpport.add(update);
                    indexId = sysDept.getDeptId().intValue();
                    ruleDeptId = sysDept.getDeptId();
                    if (i == sysDeptList.size() - 1)
                    {
                        //表示到最后一个了。从第一个开始，进下一轮循环
                        indexId = sysDeptList.get(0).getDeptId().intValue() - 1;
                    }
                    break;
                }
            }
        }
        JbOpportunityPolling polling = new JbOpportunityPolling();
        polling.setDeptId(deptId);
        polling.setRelationId(ruleDeptId);
        polling.setDataType(Constants.PUBLIC_NUMBER_0);
        if (ObjectUtils.isNotEmpty(pid))
        {
            //修改循环记录表
            polling.setId(pid);
        }
        pollingList.add(polling);
    }

    /**
     * 单个部门循环处理归属小组
     *
     * @param deptId
     * @param jbOpportunities
     * @param sysUserList
     * @param updateOpport
     * @param pollingList
     */
    private void updateOpportByUser(
            Long deptId,
            List<JbOpportunityPollingVo> jbOpportunities,
            List<SysUser> sysUserList,
            List<JbOpportunity> updateOpport,
            List<JbOpportunityPolling> pollingList)
    {
        //循环最后一个执行小组的id
        JbOpportunityPollingVo jbOpportunityPollingVo = jbOpportunities.get(0);
        Long businessManagerId = jbOpportunityPollingVo.getRelationId();
        Long pid = jbOpportunityPollingVo.getPid();
        //默认小组的第一个
        int indexId = sysUserList.get(0).getUserId().intValue() - 1;
        if (ObjectUtils.isNotEmpty(businessManagerId))
        {
            //有轮询记录，继续走一下
            indexId = businessManagerId.intValue();
        }
        Long ruleDeptId = 0L;
        for (JbOpportunityPollingVo jbOpportunity : jbOpportunities)
        {
            for (int i = 0; i < sysUserList.size(); i++)
            {
                SysUser sysUser = sysUserList.get(i);
                if (sysUser.getUserId().intValue() > indexId)
                {
                    //添加数据
                    JbOpportunity update = new JbOpportunity();
                    update.setId(jbOpportunity.getId());
                    update.setBusinessManagerId(sysUser.getUserId());
                    update.setOpportunityDataType(Constants.PUBLIC_NUMBER_3);
                    update.setDistributionType(Constants.PUBLIC_NUMBER_0.toString());
                    update.setDistributionStatus(Long.valueOf(Constants.PUBLIC_NUMBER_0));
                    update.setDistributionTime(new Date());
                    updateOpport.add(update);
                    indexId = sysUser.getUserId().intValue();
                    ruleDeptId = sysUser.getUserId();
                    if (i == sysUserList.size() - 1)
                    {
                        //表示到最后一个了。从第一个开始，进下一轮循环
                        indexId = sysUserList.get(0).getUserId().intValue() - 1;
                    }
                    break;
                }
            }
        }
        JbOpportunityPolling polling = new JbOpportunityPolling();
        polling.setDeptId(deptId);
        polling.setRelationId(ruleDeptId);
        polling.setDataType(Constants.PUBLIC_NUMBER_1);
        if (ObjectUtils.isNotEmpty(pid))
        {
            //修改循环记录表
            polling.setId(pid);
        }
        pollingList.add(polling);
    }

    /**
     * 查询全部规则 根据部门主键,规则编码
     *
     * @param ids      部门主键
     * @param rulesCod 规则编码
     * @return
     */
    @Override
    public List<JbOpportunityRules> listAllByDeptIds(List<Long> ids, String rulesCod)
    {
        LambdaQueryWrapper<JbOpportunityRules> select = new LambdaQueryWrapper<>();
        select.in(JbOpportunityRules::getDeptId, ids)
                .eq(JbOpportunityRules::getRulesCod, rulesCod);
        return baseMapper.selectList(select);
    }

    @Override
    public void offlinePublicRule()
    {
        long currentTime = System.currentTimeMillis();
        log.info("===========线下商机规则执行-{},{}", LocalDateTime.now());
        StringJoiner sql = new StringJoiner(" ").add("""
                SELECT
                	jo.id,
                	jor.dept_id,
                	jor.execution_content\s
                FROM
                	jb_opportunity jo
                	INNER JOIN sys_dept sd on jo.dept_id=sd.parent_id
                	INNER JOIN jb_opportunity_rules jor ON sd.dept_id = jor.dept_id\s
                WHERE
                	jo.del_flag = 0\s
                	AND jo.opportunity_data_type = 0\s
                	AND jo.opportunity_channel = 1002\s
                	AND jor.execution_type = 1001\s
                """);
        sql.add(String.format("	AND jor.rules_cod = '%s'", Constants.OFFLINE_OPPORTUNITY));
        List<JbCustomerPublicRule> list = joSqlUtil.jsonToEntity(baseMapper.findJson(sql.toString()),
                JbCustomerPublicRule.class);

        if (ObjectUtils.isNotEmpty(list))
        {
            //线下公共商家，匹配上后，直接修改为配置的部门id
            List<JbOpportunity> updateOpport = Lists.newArrayList();
            list.forEach(a ->
            {
                JbOpportunity update = new JbOpportunity();
                update.setId(a.getId());
                update.setDepartmentId(a.getDeptId());
                update.setOpportunityDataType(Constants.PUBLIC_NUMBER_1);
                update.setDistributionType(Constants.PUBLIC_NUMBER_0.toString());
                update.setDistributionTime(new Date());
                updateOpport.add(update);
            });
            log.info("======定时修改线下商机{}", updateOpport);
            boolean b = jbOpportunityService.updateBatchById(updateOpport);
            log.info("======定时修改线下商机{}", b);
        }
        log.info("===========小组商机执行结束-{},{}", LocalDateTime.now(), System.currentTimeMillis() - currentTime);
    }
}
